package com.offcn.search.service.impl;

import com.alibaba.fastjson.JSON;
import com.offcn.entity.Result;
import com.offcn.search.dao.SkuEsMapper;
import com.offcn.search.pojo.SkuInfo;
import com.offcn.search.service.SkuService;
import com.offcn.sellergoods.feign.SkuFeign;
import com.offcn.sellergoods.pojo.Item;
import org.apache.commons.lang.StringUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.*;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * @author ld
 * @date 2021/9/14 15:16
 */
@Service
public class SkuServiceimpl implements SkuService {

    @Autowired
    private SkuEsMapper skuEsMapper;

    @Autowired
    private SkuFeign skuFeign;

    @Autowired
    private ElasticsearchRestTemplate elasticsearchRestTemplate;

    @Override
    public void importSku() {

        //调用feign
        Result<List<Item>> result = skuFeign.findByStatus("1");
        //转为实体类
        List<SkuInfo> skuInfos = JSON.parseArray(JSON.toJSONString(result.getData()), SkuInfo.class);
        //遍历
        for (SkuInfo skuInfo : skuInfos) {
            //获取规格
            Map<String, Object> map = JSON.parseObject(skuInfo.getSpec(), Map.class);
            //设置到map中
            skuInfo.setSpecMap(map);
        }
        //保存到es
        skuEsMapper.saveAll(skuInfos);
    }

    @Override
    public Map search(Map<String, String> searchMap) {
        //1.获取关键字
        String keywords = searchMap.get("keywords");
        if (StringUtils.isEmpty(keywords)) {
            keywords = "华为";
        }
        //创建构造器
        NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();
        //3.设置条件
        /**------------1.分组条件分类-------------*/
        builder.addAggregation(AggregationBuilders.terms("skuCategoryGroup").field("category"));
        /**------------2.分组条件品牌-------------*/
        builder.addAggregation(AggregationBuilders.terms("brandGoup").field("brand"));
        /**------------3.规格统计-------------*///Map<String,Set<String>>的数据结构
        builder.addAggregation(AggregationBuilders.terms("skuGroup").field("spec.keyword").size(100));
        /**------------1.分类,品牌,规格条件过滤-------------*/
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        if (searchMap != null) {
            for (String key : searchMap.keySet()) {
                //定义的数据结构
                if (key.startsWith("spec_")) {
                    //截取名字
                    boolQueryBuilder.filter(QueryBuilders.termQuery("specMap." + key.substring(5) + ".keyword", searchMap.get(key)));
                }
                //其他
                if (!StringUtils.isEmpty(searchMap.get("brand"))) {
                    boolQueryBuilder.filter(QueryBuilders.matchQuery("brand", searchMap.get("brand")));
                }
                if (!StringUtils.isEmpty(searchMap.get("category"))) {
                    boolQueryBuilder.filter(QueryBuilders.matchQuery("category", searchMap.get("category")));
                }
                //价格0-500,3000-*
                if (!StringUtils.isEmpty(searchMap.get("price"))) {
                    //分割字符串
                    String price = searchMap.get("price");
                    String[] strings = price.split("-");
                    if (!strings[1].equalsIgnoreCase("*")) {
                        boolQueryBuilder.filter(QueryBuilders.rangeQuery("price")
                                .from(strings[0],true).to(strings[1],true));
                    }else {
                        //带*
                        boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").gte(strings[0]));
                    }
                }
            }
        }
        /////关联到builder
        builder.withFilter(boolQueryBuilder);
        /**------------分页实现---------------------------*/
        Integer pageNum = null;
        Integer pageSize = null;
        if (searchMap.get("pageNum") == null) {
            pageNum = 1;
        }else {
             pageNum = Integer.parseInt(searchMap.get("pageNum"));
        }
        //页码
        if (searchMap.get("pageSize") == null) {
             pageSize = 10;
        }else {
            pageSize= Integer.parseInt(searchMap.get("pageSize"));
        }
        //////添加分页关联
        builder.withPageable(PageRequest.of(pageNum-1, pageSize));

        /**------------排序实现-------------------------*/
        String sortRule = searchMap.get("sortRule");
        String sortField = searchMap.get("sortField");
        if (!StringUtils.isEmpty(sortField) && !StringUtils.isEmpty(sortRule)) {
            builder.withSort(SortBuilders.fieldSort(sortField).order(sortRule.equals("ASC") ? SortOrder.ASC : SortOrder.DESC));
        }
        /**------------高亮实现-------------------------*/
        builder.withHighlightFields(new HighlightBuilder.Field("title"));
        builder.withHighlightBuilder(new HighlightBuilder()
                .preTags("<em style=\"color:red\">").postTags("</em>"));
        //添加搜索条件
        builder.withQuery(QueryBuilders.multiMatchQuery(keywords,
                "title", "brand", "category"));

        //3.设置查询的条件
        //使用：QueryBuilders.matchQuery("title", keywords) ，搜索华为 ---> 华为 二字可以拆分查询，
        //使用：QueryBuilders.matchPhraseQuery("title", keywords) 华为二字不拆分查询
        builder.withQuery(QueryBuilders.matchQuery("title", keywords));
        //4.查询对象--
        NativeSearchQuery query = builder.build();
        SearchHits<SkuInfo> hits = elasticsearchRestTemplate.search(query, SkuInfo.class);
        //分页封装
        SearchPage<SkuInfo> searchPage = SearchHitSupport.searchPageFor(hits, query.getPageable());
        /**------------1.分组条件分类-------------*/
        Terms terms = hits.getAggregations().get("skuCategoryGroup");
        List<String> categoryList = this.getStringCategoryList(terms);
        /**------------2.分组条件品牌-------------*/
        Terms brandTerms = hits.getAggregations().get("brandGoup");
        List<String> brandList = this.getStringBrandList(brandTerms);
        /**------------3.规格统计-------------*///Map<String,Set<String>>的数据结构
        Terms skuTerms = hits.getAggregations().get("skuGroup");
        Map<String, Set<String>> speMap = this.getStringSetMap(skuTerms);
        /**------------高亮结果-------------------------*/
        for (SearchHit<SkuInfo> searchHit : hits) {
            Map<String, List<String>> listMap = searchHit.getHighlightFields();
            //获取结果
            SkuInfo skuInfo = searchHit.getContent();
            List<String> titles = listMap.get("title");
            if (null == listMap) {
                skuInfo.setTitle(searchHit.getContent().getTitle());
            }else {
                skuInfo.setTitle(titles.get(0));
            }
        }

        //5.遍历
        List<SkuInfo> skus = new ArrayList<>();
        for (SearchHit<SkuInfo> searchHit : searchPage.getContent()) {
            SkuInfo content = searchHit.getContent();
            SkuInfo skuInfo = new SkuInfo();
            BeanUtils.copyProperties(content, skuInfo);
            skus.add(skuInfo);
        }
        //6返回结果
        Map<String, Object> map = new HashMap();
        map.put("rows", skus);
        map.put("total", hits.getTotalHits());
        map.put("totalPages", searchPage.getTotalPages());
        map.put("categoryList", categoryList);
        map.put("brandList", brandList);
        map.put("speMap", speMap);
        //分页数据保存
        map.put("pageNum", pageNum);
        map.put("pageSize", pageSize);
        //返回
        return map;
    }

    /**
     * 获取规格的方法
     * @param skuTerms
     * @return
     */
    private Map<String, Set<String>> getStringSetMap(Terms skuTerms) {
        Map<String, Set<String>> specSetMap = new HashMap<>();
        //用来装旧值
        Set<String> specList = new HashSet<>();
        if (skuTerms != null) {
            for (Terms.Bucket bucket : skuTerms.getBuckets()) {
                //buckt是字符串{"机身内存":"128G","网络":"电信4G"}
                //{"机身内存":"16G","网络":"移动2G"}
                specList.add(bucket.getKeyAsString());
            }
        }
        //循环set集合
        if (specList != null & specList.size() > 0) {
            for (String specjson : specList) {
                //{"机身内存":"16G","网络":"移动2G"}
                Map<String, String> map = JSON.parseObject(specjson, Map.class);
                for (Map.Entry<String, String> entry : map.entrySet()) {
                    String key = entry.getKey(); //规格名字
                    String value = entry.getValue();//规格选项值
                    //获取值
                    Set<String> set= specSetMap.get(key);
                    if (set == null) {
                        set = new HashSet<>();
                    }
                    //否则,直接装
                    set.add(value);
                    //直接put-----------
                    specSetMap.put(key, set);
                }
            }
        }
        return specSetMap;
    }

    private List<String> getStringBrandList(Terms brandTerms) {
        List<String> brandList = new ArrayList<>();
        if (brandTerms != null) {
            for (Terms.Bucket bucket : brandTerms.getBuckets()) {
                String keyAsString = bucket.getKeyAsString();
                brandList.add(keyAsString);
            }
        }
        return brandList;
    }

    private List<String> getStringCategoryList(Terms terms) {
        //6.遍历分组
        List<String> categoryList = new ArrayList<>();
        if (terms != null) {
            for (Terms.Bucket bucket : terms.getBuckets()) {
                //分组的值
                String keyAsString = bucket.getKeyAsString();
                categoryList.add(keyAsString);
            }
        }
        return categoryList;
    }

}
